package xuecheng.spring.boot.start.common.concurrent;

import org.springframework.boot.SpringBootConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Primary;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.ThreadPoolExecutor;

/**
 * 线程池配置
 *
 * @author PengXueCheng
 * @version 1.0.0
 * @mail yingcheng1016@gmail.com
 * @date 2019/5/25 18:14
 * @desc
 */
@SpringBootConfiguration
public class ThreadConfig {

    /**
     * 默认线程池
     */
    public static final String THREAD_POOL_DEFAULT = "thread_pool_default";
    /**
     * 备选线程池 1 号
     */
    public static final String THREAD_POOL_ALTERNATIVE_1 = "thread_pool_alternative_1";

    /**
     * 处理流程
     * 当一个任务被提交到线程池时，首先查看线程池的核心线程是否都在执行任务，否就选择一条线程执行任务，是就执行第二步。
     * 查看核心线程池是否已满，不满就创建一条线程执行任务，否则执行第三步。
     * 查看任务队列是否已满，不满就将任务存储在任务队列中，否则执行第四步。
     * 查看线程池是否已满，不满就创建一条线程执行任务，否则就按照策略处理无法执行的任务。
     * 在ThreadPoolExecutor中表现为:
     * 如果当前运行的线程数小于corePoolSize，那么就创建线程来执行任务（执行时需要获取全局锁）。
     * 如果运行的线程大于或等于corePoolSize，那么就把task加入BlockQueue。
     * 如果创建的线程数量大于BlockQueue的最大容量，那么创建新线程来执行该任务。
     * 如果创建线程导致当前运行的线程数超过maximumPoolSize，就根据饱和策略来拒绝该任务。
     */

    @Primary
    @Bean(THREAD_POOL_DEFAULT)
    public ThreadPoolTaskExecutor threadPoolDefault() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(4);
        executor.setMaxPoolSize(5000);
        executor.setQueueCapacity(0);
        // 设置线程拒绝策略(将任务给调用线程)
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        executor.initialize();
        return executor;
    }

    @Bean(THREAD_POOL_ALTERNATIVE_1)
    public ThreadPoolTaskExecutor threadPoolSupplierRequest() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(4);
        executor.setMaxPoolSize(5000);
        executor.setQueueCapacity(0);
        // 设置线程拒绝策略(将任务给调用线程)
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        executor.initialize();
        return executor;
    }

}
